/* dtc.c
 *	Client user program of distributed ticket checker in a train simulation
 *	
 *	Simulates a Ticket Checker
 */
 
 #include "syscall.h"
 
 /*============Global variables===============

-------Set Up Variables------------------------------
-----------------------------------------------------*/
const int MAXSTOPS = 10; /*How many Stops*/ /*should this become monitor variable now?*/
const int MAXPASSENGERS = 1; /*Maximum Passengers*/
const int PRICE_PER_STOP = 1; /*Price for each Stop*/
const int FIRST_CLASS_SURCHARGE = 2; /*1st Class's Extra Charge*/

/* Lock */
int nextStopLock;
int ticketCheckerLineLock;
int waitingForTrainLock[10];
int signalAttendantsLock;

/* CV */
int nextStop;
int ticketCheckerLine;
int ticketCheckerAvailable;
int waitingForTrain[10];
int signalAttendants;

/* MV */
int checkerBusy;
int psgTCWaiting[30];
int g_validatePsgNumber;
int tcPsgWaiting;
int validateTicketvalidated;
int firstClass[40]; 
int ticketPrice[40];
int passengerWaitingToBeSeated;
int numFirstClassThatBoarded;
int currentStop;
int tcTrainWaiting;
int passengersWaitingAtStop[10];
int getOnStop[40]; /* stop to get on at*/
int getOffStop[40]; /*stop to get off at*/
int numEconClassThatBoarded;
int g_totalTicketPrice;
int ticketCheckerLineLength;

/*============End of Global variables=========*/

void Ticket_Checker(void);
void setupMonitors(void);
void itoa(char arr[], int size, int val);
void Dummy(void);

int main(int argc, char *argv[])
{
	void (*ticketChecker)(void);
	void (*myDummy)(void); /*For some reason if you fork just once, nothing works*/
	PrintOut("\n\n******************TicketChecker**********************\n\n", 57);

	setupMonitors(); /*Requesting all the locks, CVs, and MVs needed by Ticket Checker client*/
	
	ticketChecker = &Ticket_Checker;
	myDummy = &Dummy;
    Fork(ticketChecker);
	Fork(myDummy);

	return;
}

void Dummy()
{
	PrintOut("Dummy Thread\n", 13);
    Exit(0);		
}

/*Requesting all the locks, CVs, and MVs needed by Train client*/
void setupMonitors()
{
	int firstClassDummy=0;
	int i;
	char indexBuf[2];
	char nameBuf[4]; /*a prefix will be put in first two slots, then the local index*/
	
	for(i=0; i<MAXSTOPS; i++)
	{
		itoa (indexBuf, 2, i);
		nameBuf[0] = 'w';
		nameBuf[1] = 't';
		nameBuf[2] = indexBuf[0];
		nameBuf[3] = indexBuf[1]; /* Example name: "wt6"*/
		waitingForTrainLock[i] = CreateLock (nameBuf, 4, 1);
		waitingForTrain[i] = CreateCV (nameBuf, 4, 1);
		
		nameBuf[0] = 'w';
		nameBuf[1] = 's'; /* Wait at Stop*/
		passengersWaitingAtStop[i] = CreateMV (nameBuf, 4, 1);
		SetMV(passengersWaitingAtStop[i], 0);
	}

	for (i = 0; i < MAXPASSENGERS; i ++){
	
		itoa (indexBuf, 2, i);
		nameBuf[0] = 'p';
		nameBuf[1] = 't';
		nameBuf[2] = indexBuf[0];
		nameBuf[3] = indexBuf[1]; /* Example name: "pt6"*/
		firstClassDummy=RandomInt()%3;
		
		psgTCWaiting[i] = CreateMV (nameBuf, 4, 1);
		SetMV(psgTCWaiting[i], 0);
		
		nameBuf[0] = 'f';
		nameBuf[1] = 'c'; /* firstClass */
		firstClass[i] = CreateMV(nameBuf, 4, 1);
		
		nameBuf[0] = 't';
		nameBuf[1] = 'p'; /* ticketPrice */
		ticketPrice[i] = CreateMV(nameBuf, 4, 1);
		
		itoa (indexBuf, 2, i);
		nameBuf[0] = 'p';
		nameBuf[1] = 'o';
		nameBuf[2] = indexBuf[0];
		nameBuf[3] = indexBuf[1]; /* Example name: "po6"*/
		
		/*Randomly assign a starting stop such that it is at most 2 stops from the end*/
		getOnStop[i] = CreateMV(nameBuf, 4, 1);
		SetMV(getOnStop[i], RandomInt()%(MAXSTOPS-1) );
		
		nameBuf[0] = 'p';
		nameBuf[1] = 'f'; /* getOff */
		/*Randomly assign a get off stop such that it ranges from the start stop to the end*/
		getOffStop[i] = CreateMV(nameBuf, 4, 1);
		SetMV(getOffStop[i], RandomInt()%(MAXSTOPS- GetMV(getOnStop[i])-1)+ 1 + GetMV(getOnStop[i]) );
		
		/*Calculate the ticket price and set passenger class status*/
		if (firstClassDummy==1)
		{
			SetMV(firstClass[i], 1);
			SetMV(ticketPrice[i], (GetMV(getOffStop[i]) - GetMV(getOnStop[i]))*(PRICE_PER_STOP + FIRST_CLASS_SURCHARGE));
		}
		else
		{
			SetMV(firstClass[i], 0);
			SetMV(ticketPrice[i], (GetMV(getOffStop[i])-GetMV(getOnStop[i]))*(PRICE_PER_STOP));
		}
		
		SetMV(passengersWaitingAtStop[GetMV(getOnStop[i])], GetMV(passengersWaitingAtStop[GetMV(getOnStop[i])]) + 1);
	}
	
	/*Locks*/
	nextStopLock = CreateLock("nextStopLock", 12, 1); /*also created by train, should return index*/
	signalAttendantsLock = CreateLock ("signalAttenLock", 15, 1);

	/*CVs*/
	nextStop = CreateCV("nextStopCV", 10, 1); /*also created by train, should return index*/
	signalAttendants = CreateCV ("signalAttendants", 16, 1);

	/*MVs*/
	currentStop = CreateMV("currentStopMV", 13, 1); /*also created by train, should return index*/
	
	checkerBusy = CreateMV("checkerBusyMV", 13, 1);

	/*--Ticket Checker waiting on Train--*/
	ticketCheckerLineLock = CreateLock ("tCLineLock", 10, 0);
	
	tcTrainWaiting = CreateMV("tcTrainWaitingMV", 16, 1);

	ticketCheckerLine = CreateCV ("ticketCheckerLineCV", 19, 0);
	ticketCheckerAvailable = CreateCV ("tCAvailable", 11, 0);
	
	g_validatePsgNumber = CreateMV("g_validatePsgNumber", 19, 1);
	SetMV(g_validatePsgNumber, 0);
	
	tcPsgWaiting = CreateMV("tcPsgWaiting", 12, 1);
	SetMV(tcPsgWaiting, 0);
	
	validateTicketvalidated = CreateMV("vTicketvalidated", 16, 1);
	SetMV(validateTicketvalidated, 0);

	passengerWaitingToBeSeated = CreateMV("psgWaitToBeSeated", 17, 1);
	SetMV(passengerWaitingToBeSeated, 0);
	
	numFirstClassThatBoarded = CreateMV("nFClassThatBoarded", 18, 1);
	SetMV(numFirstClassThatBoarded,0); 
	
	numEconClassThatBoarded = CreateMV("nECThatBoardedMV", 16, 1);
	SetMV(numEconClassThatBoarded,0); 
	
	g_totalTicketPrice = CreateMV("g_totalTicketPrice", 18, 1);
	SetMV(g_totalTicketPrice, 0);
	
	ticketCheckerLineLength = CreateMV("ticketCheckerLL", 15, 1);
	SetMV(ticketCheckerLineLength, 0);
}


void Ticket_Checker()
{
	char psgBuf[2];
	char stopBuf[2];
	int i;

	while(1)
	{
		
		Acquire(nextStopLock,0);
		
		/*Wait for signal from conductor*/
		SetMV(tcTrainWaiting,1);
		Wait(nextStop, nextStopLock,0);
		/*PrintOut("2.5 TC HERE!!\n", 14);*/
		/*Exit the monitor for arriving at next stop*/
		Release(nextStopLock,0);
		/*Received signal from conductor that we're at next stop*/
		/*Acquire lock for passengers waiting at stop*/
		Acquire(waitingForTrainLock[GetMV(currentStop)],0);
		/*Acquire locks for the ticket checker line*/
		Acquire(ticketCheckerLineLock,0);
	
		Broadcast(waitingForTrain[GetMV(currentStop)], waitingForTrainLock[GetMV(currentStop)],0);
		
		/*Release the lock and exit the monitor for those waiting at this stop*/
		Release(waitingForTrainLock[GetMV(currentStop)],0);
		
		/*Make myself available for passengers waiting at stop whenever cpu gives this thread control again*/
		SetMV(checkerBusy,0); 
		
		while(GetMV(passengersWaitingAtStop[GetMV(currentStop)])>0)
		{
			SetMV(tcPsgWaiting, 1);
			Wait(ticketCheckerAvailable, ticketCheckerLineLock,0);
			/*So since I'm this far the passenger has woken me up and shared ticket data is ready*/
			if((GetMV(getOnStop[GetMV(g_validatePsgNumber)])== GetMV(currentStop))&&
				(GetMV(getOffStop[GetMV(g_validatePsgNumber)]) <= MAXSTOPS))
			{
				/*Set ticket data as valid*/
				SetMV(validateTicketvalidated, 1);
				/*Ticket Checker validate the ticket of passenger*/
				/*And account for the passenger*/
				if(GetMV(firstClass[GetMV(g_validatePsgNumber)]))
				{
					SetMV(numFirstClassThatBoarded, GetMV(numFirstClassThatBoarded)+1);
					SetMV(passengerWaitingToBeSeated, GetMV(passengerWaitingToBeSeated) +1 );
				}
				else
				{
					SetMV(numEconClassThatBoarded, GetMV(numEconClassThatBoarded) + 1 );
					SetMV(passengerWaitingToBeSeated, GetMV(passengerWaitingToBeSeated) + 1 );
				}
				itoa (psgBuf, 2, GetMV(g_validatePsgNumber));
				itoa (stopBuf, 2, GetMV(currentStop));
				PrintOut("Ticket Checker validate the ticket of passenger [", 49);
				PrintOut(psgBuf, 2);
				PrintOut("] of Train [0] at stop number [", 31);
				PrintOut(stopBuf, 2);
				PrintOut("]\n",2);
				/*Add up ticket prices total*/
				SetMV(g_totalTicketPrice,  GetMV(g_totalTicketPrice)+GetMV(ticketPrice[GetMV(g_validatePsgNumber)]));
			}
			else
			{
				/*Set ticket data as invalid*/
				SetMV(validateTicketvalidated, 0);
				itoa (psgBuf, 2, GetMV(g_validatePsgNumber));
				itoa (stopBuf, 2, GetMV(currentStop));
				PrintOut("Ticket Checker invalidate the ticket of passenger [", 51);
				PrintOut(psgBuf, 2);
				PrintOut("] of Train [0] at stop number [", 31);
				PrintOut(stopBuf, 2);
				PrintOut("]\n",2);
			}
			while (GetMV(psgTCWaiting[GetMV(g_validatePsgNumber)]) ==0){
			}
			SetMV(psgTCWaiting[GetMV(g_validatePsgNumber)], 0);
			/*Signal passenger that ticket data has been verified*/
			Signal(ticketCheckerAvailable, ticketCheckerLineLock,0);
			/*Decrement number of passengers waiting at stop*/
			SetMV(passengersWaitingAtStop[GetMV(currentStop)], GetMV(passengersWaitingAtStop[GetMV(currentStop)])-1);
			/*Make myself available for next passenger in wait queue*/
			if(GetMV(ticketCheckerLineLength)==0)	
				SetMV(checkerBusy, 0);
			/*Or signal those remaining on the line*/
			else
				Signal(ticketCheckerLine, ticketCheckerLineLock,0);
		
			/*Exit line monitor*/
			Release(ticketCheckerLineLock,0);
			/*Enter monitor for initating seat assignment*/
			Acquire(signalAttendantsLock,0);
		
			Broadcast(signalAttendants, signalAttendantsLock,0);
			
			/*Exit the monitor for seat assignment*/
			Release(signalAttendantsLock,0);
		}
		
		/*Exit line monitor*/
			Release(ticketCheckerLineLock,0);
		
	}
	Exit(0);
}
/* ********End Train****************************/

int myexp ( int count ) {
  int i, val=1;
  for (i=0; i<count; i++ ) {
    val = val * 10;
  }
  return val;
}

void itoa( char arr[], int size, int val ) {
  int i, max, dig, subval, loc;
  for (i=0; i<size; i++ ) {
    arr[i] = '\0';
  }

  for ( i=1; i<=10; i++ ) {
    if (( val / myexp(i) ) == 0 ) {
      max = i-1;
      break;
    }
  }

  subval = 0;
  loc = 0;
  for ( i=max; i>=0; i-- ) {
    dig = 48 + ((val-subval) / myexp(i));
    subval += (dig-48) * myexp(i);
    arr[loc] = dig;
    loc++;
  }

  return;
}
